#! /usr/bin/env python
# -*- coding: utf-8 -*-
'''
Created on 30 déc. 2011

@author: nathanael
'''

from PyQt4 import QtGui

import time

from pybible.core.regex import RegexPattern, CustomWordPattern
from pybible.core.find import FindKernel, RequestFactory
from pybible.core.result import ResultsFactory

class FindWidget(QtGui.QWidget):
    """Widget to look for something.
    
    """

    def __init__(self, data, lingual=None, *argv, **kw):
        """Constructor
        """
        super(FindWidget, self).__init__(*argv, **kw)

        # default options
        self._case_sensitive = False
        self._emphasis_sensitive = False
        self._whole_word = False
        self._regex = False

        self._data = data
        self._results = None

        self._lingual = lingual
        self._request_factory = RequestFactory()
        self._find_kernel = FindKernel()

        self.init_gui()

    def init_gui(self):
        """Draw widget to look for something.
        
        +------------------+------------------+
        |  TEXT FIND       |                  |
        |                  |                  |
        |  opt 1           | HERE RESULTS     |
        |  opt 2           | LIST             |
        |                  |                  |
        |  opt x           |                  |
        |                  |                  |
        |    Ok Cancel     |                  |
        +-------------------------------------+
        
        """

        #=======================================================================
        # Action box 
        #=======================================================================
        ok_button = QtGui.QPushButton("OK")
        ok_button.clicked.connect(self.action_ok)
        cancel_button = QtGui.QPushButton("Cancel")
        cancel_button.clicked.connect(self.action_cancel)

        actions_box = QtGui.QHBoxLayout()
        actions_box.addStretch(1)
        actions_box.addWidget(ok_button)
        actions_box.addWidget(cancel_button)

        #=======================================================================
        # Input box 
        #=======================================================================
        opts_box = QtGui.QVBoxLayout()
        opts_box.addStretch(1)
        # pattern found
        self._pattern_edit = QtGui.QLineEdit()
        opts_box.addWidget(self._pattern_edit)

        # options
        self.new_option(opts_box, 'case_sensitive')
        self.new_option(opts_box, 'emphasis_sensitive')
        self.new_option(opts_box, 'whole_word')
        self.new_option(opts_box, 'regex', 'Regular expressions')


        #=======================================================================
        # found board
        #=======================================================================
        found_board = QtGui.QVBoxLayout()
        found_board.addStretch(1)
        found_board.addLayout(opts_box)
        found_board.addLayout(actions_box)

        #=======================================================================
        # result 
        #=======================================================================
        self._results = QtGui.QListWidget()

        #=======================================================================
        # Global box
        #=======================================================================
        global_box = QtGui.QHBoxLayout()
        global_box.addStretch(1)
        global_box.addLayout(found_board)
        global_box.addWidget(self._results)
        self.setLayout(global_box)
        self.setWindowTitle('Find')
        self.show()

    def new_option(self, box, opt_name, label=None):
        """Build and return a new options
        
        INPUTS:
            box: QT box where are set the new options
            opt_name: The options attribute name where are stored the option value.
            label: The option name display. If no define build from opt_name.
            
        """
        if not hasattr(self, "_%s" % opt_name):
            raise ValueError("Try to build option ('%s') without preset value!" % opt_name)

        if label is None:
            label = opt_name.replace('_', ' ').capitalize()

        opt = QtGui.QCheckBox(label)
        opt.stateChanged.connect(self.get_change_option(opt_name))
        if getattr(self, "_%s" % opt_name):
            opt.toggle()
        box.addWidget(opt)

    def get_change_option(self, opt_name):
        """Return callable object relative to given options name.
        
        INPUTS:
            opt_name: The options attribute name where are stored the option value.
            
        """
        def change_options_(state):
            print "Option %s change to %s" % (opt_name, bool(state))
            setattr(self, opt_name, bool(state))
        return change_options_


    def get_pattern_sting(self):
        "Read user input pattern."
        return unicode(self._pattern_edit.text())

    def get_request(self):
        # build regex pattern
        s = self.get_pattern_sting()
        if self._regex:
            builder = RegexPattern
        else:
            if self._emphasis_sensitive and self._lingual is not None:
                emphasis_characters = self._lingual.get_emphasis()
            else:
                emphasis_characters = []
            builder = CustomWordPattern(whole_word=self._whole_word,
                                        case_sensitive=self._case_sensitive,
                                        emphasis_characters=emphasis_characters)

        return self._request_factory(builder.build_regex(s))

    def action_ok(self):
        """Ok clicked action.
        
        Events: Found action, check and run.
        """

        pattern = self.get_pattern_sting()
        if not pattern:
            raise ValueError("Invalid pattern (%s)!" % (pattern))

        regex = self.get_request()

        self._find_kernel.clear()
        self._find_kernel.set_request(regex)
        if self._lingual is not None:
            booksname = self._lingual.get_books_name(short=True)
            self._find_kernel._factory.reinit(booksname=booksname,
                                              data=self._data)

        t = time.time()
        self._find_kernel.find(self._data, wait=True)
        print "found in %f" % (time.time() - t)


    def action_cancel(self):
        """Cancel clicked action.
        
        Events:
            - Clean all.
        """

        self._pattern_edit.clear()
        self._results.clear()


def main():
    import sys, os

    from pybible.data import DATA_PATH
    from pybible.core.data import openBook

    bible = openBook(os.path.join(DATA_PATH, 'french_jn_darby.xml'))

    app = QtGui.QApplication(sys.argv)
    ex = FindWidget(bible.get_part().get_data())
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()
